import { createStore, ObservableMap } from '@stencil/store';
import { QXEvent } from 'qx-util';
import { IStore } from './i-store';

/**
 * 数据仓库
 *
 * @author chitanda
 * @date 2021-05-12 18:05:15
 * @export
 * @abstract
 * @class StoreBase
 * @implements {IStore<State>}
 * @template State
 */
export abstract class StoreBase<State = any> implements IStore<State> {
  /**
   * 存储
   *
   * @protected
   * @type {ObservableMap<State>}
   * @memberof IBzResourceAllocationStore
   */
  protected store: ObservableMap<State>;

  /**
   * 状态
   *
   * @type {State}
   * @memberof IBzResourceAllocationStore
   */
  readonly data: State;

  /**
   * 事件
   *
   * @protected
   * @type {QXEvent<any>}
   * @memberof IBzResourceAllocationStore
   */
  protected evt: QXEvent<State> = new QXEvent(3000);

  /**
   * Creates an instance of IBzResourceAllocationStore.
   * @memberof IBzResourceAllocationStore
   */
  constructor() {
    this.store = createStore<State>(this.getState());
    this.data = this.store.state;
    this.init();
  }

  /**
   * 初始化
   *
   * @protected
   * @memberof StoreBase
   */
  protected init(): void {
    for (const key in this.data) {
      this.store.onChange(key, val => {
        this.evt.emit(key, val);
        (this.evt as any).emit('change', key, val);
      });
    }
  }

  /**
   * 获取状态对象实例
   *
   * @protected
   * @abstract
   * @return {*}  {State}
   * @memberof StoreBase
   */
  protected abstract getState(): State;

  /**
   * 订阅事件
   *
   * @template K
   * @param {K} name
   * @param {(arg?: State[K]) => void} cb
   * @memberof StoreBase
   */
  on<K extends keyof State>(name: K, cb: (arg?: State[K]) => void): void {
    return this.evt.on(name, cb);
  }

  /**
   * 取消订阅事件
   *
   * @template K
   * @param {K} name
   * @param {(arg?: State[K]) => void} cb
   * @memberof StoreBase
   */
  off<K extends keyof State>(name: K, cb: (arg?: State[K]) => void): void {
    return this.evt.off(name, cb);
  }

  /**
   * 订阅store变化
   *
   * @param {(key: keyof State, val: State[keyof State]) => void} cb
   * @memberof StoreBase
   */
  onChange(cb: (key: keyof State, val: State[keyof State]) => void): void {
    this.evt.on('change' as any, cb as any);
  }

  /**
   * 取消订阅store变化
   *
   * @param {(key: keyof State, val: State[keyof State]) => void} cb
   * @memberof StoreBase
   */
  offChange(cb: (key: keyof State, val: State[keyof State]) => void): void {
    this.evt.off('change' as any, cb as any);
  }
}
